//
//  GKDPageView.m
//  sojex
//
//  Created by longxdragon on 2017/7/4.
//  Copyright © 2017年 finance. All rights reserved.
//

#import "GKDPageView.h"
#import "GKDPageViewController.h"
#import "UIView+DDAdd.h"
#import "UIViewController+GKDPageItem.h"

static NSInteger const kGKDPageViewItemTag = 100;


@interface GKDZoomScrollView : UIScrollView

@end

@implementation GKDZoomScrollView

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if ([self panGestureShouldBegin:gestureRecognizer]) {
        return YES;
    }
    return NO;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if ([self panGestureShouldBegin:gestureRecognizer]) {
        return NO;
    }
    return YES;
}

- (BOOL)panGestureShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer == self.panGestureRecognizer) {
        UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;
        CGPoint velocity = [pan velocityInView:self];
        UIGestureRecognizerState state = gestureRecognizer.state;
        if (UIGestureRecognizerStateBegan == state || UIGestureRecognizerStatePossible == state) {
            CGPoint location = [gestureRecognizer locationInView:self];
            if (velocity.x > 0 && location.x < 90 && self.contentOffset.x <= 0) {
                return YES;
            }
            if (velocity.x < 0 && self.contentOffset.x >= self.contentSize.width - self.bounds.size.width) {
                return YES;
            }
        }
    }
    return NO;
}

@end


@interface GKDPageView () <UIScrollViewDelegate, UIGestureRecognizerDelegate>

@property (nonatomic, weak) UIViewController *containerViewController;
@property (nonatomic, strong) GKDPageViewController *pageViewController;

@property (nonatomic, strong) GKDZoomScrollView *scrollView;
@property (nonatomic, strong) UIView *mainView;
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, UIViewController *> *controllers;
@property (nonatomic, assign) NSInteger pageNumbers;
@property (nonatomic, assign) NSInteger currentIndex;
@property (nonatomic, assign) BOOL appear;

@end

@implementation GKDPageView {
    CGFloat _lastContentoffsetX;
}

- (instancetype)initWithContainerViewController:(UIViewController *)containerViewController {
    self = [super init];
    if (self) {
        self.containerViewController = containerViewController;
        self.mainView = self.pageViewController.view;

        [self configueValues];
        [self configueViews];
    }
    return self;
}

- (void)configueValues {
    self.currentIndex = 0;
}

- (void)configueViews {
    [self.mainView addSubview:self.scrollView];
}

#pragma mark - Super Overrite

- (void)layoutSubviews {
    [super layoutSubviews];
    [self _layoutSubviews];
}

- (void)_layoutSubviews {
    self.mainView.frame = self.bounds;
    
    self.scrollView.frame = self.mainView.bounds;
    self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * self.pageNumbers, self.scrollView.height);
    self.scrollView.contentOffset = CGPointMake(self.scrollView.frame.size.width * self.currentIndex, 0);
    
    for (UIView *subView in self.scrollView.subviews) {
        NSInteger index = subView.tag - kGKDPageViewItemTag;
        subView.frame = (CGRect){{self.scrollView.frame.size.width * index, 0}, self.scrollView.frame.size};
    }
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [self.containerViewController addChildViewController:self.pageViewController];
    [self addSubview:self.mainView];
    [self reloadData];
}

#pragma mark - Public Methods

- (void)reloadData {
    NSInteger number = 0;
    if (self.dataSource && [self.dataSource respondsToSelector:@selector(numberOfViewControllersInPageView)]) {
        number = [self.dataSource numberOfViewControllersInPageView];
    }
    if (number <= 0) return;
    self.pageNumbers = number;
    
    if (_activeIndex > 0) {
        self.currentIndex = _activeIndex;
        _activeIndex = 0;
    }
    if (self.currentIndex < 0 || self.currentIndex >= number) {
        self.currentIndex = 0;
    }
    
    for (UIViewController *vc in self.controllers.allValues) {
        [vc removeFromParentViewController];
        [vc.view removeFromSuperview];
    }
    [self.controllers removeAllObjects];
    
    [self.scrollView setContentSize:CGSizeMake(self.bounds.size.width * number, self.scrollView.height)];
    [self.scrollView setContentOffset:CGPointMake(self.currentIndex * self.bounds.size.width, 0)];
    
    [self pageViewWillAppear:self.currentIndex];
    [self pageViewDidAppear:self.currentIndex];
}

- (void)setActiveIndex:(NSInteger)activeIndex {
    [self setActivIndexAtIndex:activeIndex duration:0.25 animated:YES];
}

- (void)setActiveIndex:(NSInteger)activeIndex animated:(BOOL)animated {
    [self setActivIndexAtIndex:activeIndex duration:0.25 animated:animated];
}

- (void)setActivIndexAtIndex:(NSInteger)activeIndex duration:(NSTimeInterval)duration animated:(BOOL)animated {
    _activeIndex = activeIndex;
    
    if (activeIndex < 0 || activeIndex >= self.pageNumbers) {
        return;
    }
    if (activeIndex != self.currentIndex) {
        NSInteger preIndex = self.currentIndex;
        self.currentIndex = activeIndex;

        if (animated) {
            [UIView animateWithDuration:duration animations:^{
                [self.scrollView setContentOffset:CGPointMake(self.scrollView.frame.size.width * activeIndex, 0)];
            } completion:^(BOOL finished) {
                [self pageViewWillAppear:activeIndex];
                [self pageViewWillDisappear:preIndex];
                [self pageViewDidDisappear:preIndex];
                [self pageViewDidAppear:activeIndex];
            }];
        }else {
            [self.scrollView setContentOffset:CGPointMake(self.scrollView.frame.size.width * activeIndex, 0)];
            [self pageViewWillAppear:activeIndex];
            [self pageViewWillDisappear:preIndex];
            [self pageViewDidDisappear:preIndex];
            [self pageViewDidAppear:activeIndex];
        }
    }
}

- (void)setScrollEnable:(BOOL)scrollEnable {
    _scrollEnable = scrollEnable;
    self.scrollView.scrollEnabled = scrollEnable;
}

- (UIViewController *)activeController {
    return self.controllers[@(self.currentIndex)];
}

- (void)showViewController:(NSInteger)index {
    [self pageViewWillAppear:index];
    [self pageViewDidAppear:index];
}

- (void)enumerateControllerUsingBlock:(void (^)(UIViewController *, NSUInteger, BOOL *))block {
    [[self.controllers allValues] enumerateObjectsUsingBlock:block];
}

#pragma mark - Private Methods

- (void)pageViewWillAppear:(NSInteger)index {
    if (self.pageNumbers <= 0) {
        return;
    }
    UIViewController *vc = self.controllers[@(index)];
    if (vc) {
        if (self.appear) {
            [vc beginAppearanceTransition:YES animated:YES];
        }
    } else {
        vc = [self.dataSource viewControllerAtIndex:index];
        if (!vc) {
            vc = [[UIViewController alloc] init];
        }
        self.controllers[@(index)] = vc;
        
        UIView *view = vc.view;
        view.frame = CGRectMake(self.bounds.size.width * index, 0, self.bounds.size.width, self.bounds.size.height);
        view.tag = index + kGKDPageViewItemTag;
        
        [self.scrollView addSubview:view];
        [self.pageViewController addChildViewController:vc];
        
        if (self.appear) {
            [vc beginAppearanceTransition:YES animated:YES];
        }
    }
}

- (void)pageViewDidAppear:(NSInteger)index {
    if (self.pageNumbers <= 0) {
        return;
    }
    UIViewController *vc = self.controllers[@(index)];
    if (vc) {
        [vc setIsAppear:YES];
        
        if (self.appear) {
            [vc endAppearanceTransition];
        }
    }
}

- (void)pageViewWillDisappear:(NSInteger)index {
    if (self.pageNumbers <= 0) {
        return;
    }
    UIViewController *vc = self.controllers[@(index)];
    if (vc) {
        if (self.appear) {
            [vc beginAppearanceTransition:NO animated:YES];
        }
    }
}

- (void)pageViewDidDisappear:(NSInteger)index {
    if (self.pageNumbers <= 0) {
        return;
    }
    UIViewController *vc = self.controllers[@(index)];
    if (vc) {
        [vc setIsAppear:NO];
        
        if (self.appear) {
            [vc endAppearanceTransition];
        }
    }
}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    CGFloat offsetX = scrollView.contentOffset.x;
    NSInteger index = offsetX / scrollView.bounds.size.width;
    if (index == self.currentIndex) {
        return;
    }
    NSInteger preIndex = self.currentIndex;
    self.currentIndex = index;
    
    if ([self.delegate respondsToSelector:@selector(pageView:didSelectedAtIndex:)]) {
        [self.delegate pageView:self didSelectedAtIndex:index];
    }
    
    [self pageViewWillAppear:index];
    [self pageViewWillDisappear:preIndex];
    [self pageViewDidDisappear:preIndex];
    [self pageViewDidAppear:index];
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
    _lastContentoffsetX = scrollView.contentOffset.x;
}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (self.scrollView != scrollView && self.pageNumbers <= 0) {
        return;
    }
    
    CGFloat offsetX = self.scrollView.contentOffset.x;
    CGFloat width = CGRectGetWidth(self.scrollView.frame);
    NSInteger floorIndex = floor(offsetX / width);
    CGFloat progress = offsetX / width - floorIndex;
    
    if (floorIndex < 0 || floorIndex > self.pageNumbers) {
        return;
    }
    NSInteger currentIndex = 0, nextIndex = 0;
    if (offsetX > _lastContentoffsetX) {
        // turn right
        if (floorIndex > self.pageNumbers - 1) {
            return;
        }
        currentIndex = floorIndex;
        nextIndex = (int)((offsetX + width - 0.1) / width);
    } else {
        // turn left
        currentIndex = ceilf(offsetX / width);
        nextIndex = (int)(offsetX / width);
        progress = 1.0 - progress;
    }
    if ([self.delegate respondsToSelector:@selector(pageViewDidScrollFormIndex:toIndex:progress:)]) {
        [self.delegate pageViewDidScrollFormIndex:currentIndex toIndex:nextIndex progress:progress];
    }
}

#pragma mark - Property Getter

- (UIScrollView *)scrollView {
    if (!_scrollView) {
        _scrollView = [[GKDZoomScrollView alloc] initWithFrame:self.bounds];
        _scrollView.showsVerticalScrollIndicator = NO;
        _scrollView.showsHorizontalScrollIndicator = NO;
        _scrollView.pagingEnabled = YES;
        _scrollView.scrollsToTop = NO;
        _scrollView.delegate = self;
        _scrollView.bounces = NO;
        _scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
    }
    return _scrollView;
}

- (NSMutableDictionary<NSNumber *, UIViewController *> *)controllers {
    if (!_controllers) {
        _controllers = [NSMutableDictionary dictionary];
    }
    return _controllers;
}

- (GKDPageViewController *)pageViewController {
    if (!_pageViewController) {
        _pageViewController = [[GKDPageViewController alloc] init];
        @weakify(self);
        _pageViewController.pageViewWillAppear = ^(BOOL animated) {
            @strongify(self);
            [self setAppear:YES];
            [self pageViewWillAppear:self.currentIndex];
        };
        _pageViewController.pageViewDidAppear = ^(BOOL animated) {
            @strongify(self);
            [self pageViewDidAppear:self.currentIndex];
        };
        _pageViewController.pageViewWillDisappear = ^(BOOL animated) {
            @strongify(self);
            [self pageViewWillDisappear:self.currentIndex];
        };
        _pageViewController.pageViewDidDisappear = ^(BOOL animated) {
            @strongify(self);
            [self pageViewDidDisappear:self.currentIndex];
            [self setAppear:NO];
        };
    }
    return _pageViewController;
}

@end
